﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Little_Tower_Defense.FieldTypes;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using Little_Tower_Defense.Builings;

namespace Little_Tower_Defense
{
    /// <summary>
    /// A drawable component, that represents a level of the game.
    /// Manages the grid layout.
    /// </summary>
    class Level : DrawableGameComponent
    {
        public new LittleTowerDefense Game;
        public int OffsetX;
        public int OffsetY;
        public int BlockSize;
        public Rectangle Area;

        List<Field> fields;
        Dictionary<string, Texture2D> fieldTextures;
        List<DrawableGameComponent> drawableComponents;
        GameComponentCollection components { get; set; }
        Player player;
        List<IBuilding> buildings;

        public Level(LittleTowerDefense game, Rectangle gameArea)
            : base(game)
        {
            this.Game = game;
            this.Area = gameArea;
            components = new GameComponentCollection();
            drawableComponents = new List<DrawableGameComponent>();
            buildings = new List<IBuilding>();
            player = new Player();

            components.ComponentAdded += new EventHandler<GameComponentCollectionEventArgs>(Components_ComponentAdded);
        }

        private void Components_ComponentAdded(object sender, GameComponentCollectionEventArgs e)
        {
            e.GameComponent.Initialize();
            // Frage: Wird hier neuer Speicher angelegt? 
            //        Ist eine DrawableGameComponent danach physikalisch zweimal vorhanden (in Components & in drawableComponents)?
            DrawableGameComponent drawableComponent = e.GameComponent as DrawableGameComponent;
            if (drawableComponent != null)
            {
                drawableComponents.Add(drawableComponent);
            }
        }

        public void Reset()
        {
            // Wird aufgerufen, wenn das Level von neuem starten soll

        }
        
        private void LoadLevel()
        {
            fields = LevelLoader.loadTextFile("TestLevel1");
        }

        private void LoadLevelTextures()
        {
            fieldTextures = new Dictionary<string, Texture2D>();
            foreach (Field field in fields)
            {
                if (!fieldTextures.ContainsKey(field.TextureName))
                    fieldTextures.Add(field.TextureName, Game.Content.Load<Texture2D>(field.TextureName));
            }
        }

        public override void Initialize()
        {
            base.Initialize();

            BlockSize = 10;

            components.Add(new LeftMouseButtonPanning(Game));
            components.Add(new ArrowKeysPanning(Game));
            components.Add(new MouseWheelScrolling(Game, this, Area));
        }

        protected override void LoadContent()
        {
            LoadLevel();
            LoadLevelTextures();
            base.LoadContent();
        }

        public override void Update(GameTime gameTime)
        {
            foreach (GameComponent component in components)
            {
                component.Update(gameTime);
            }
            base.Update(gameTime);

            // Ein paar Türmchen bauen
            if (gameTime.TotalGameTime.Seconds == 2)
            {
                addTower(new SimpleTower(Game, this, 3, 2));
            }
            if (gameTime.TotalGameTime.Seconds == 3)
            {
                addTower(new SimpleTower(Game, this, 10, 5));
            }
            if (gameTime.TotalGameTime.Seconds == 4)
            {
                addTower(new SimpleTower(Game, this, 5, 3));
            }
            if (gameTime.TotalGameTime.Seconds == 5)
            {
                addTower(new SimpleTower(Game, this, 5, 3));
            }
        }

        public override void Draw(GameTime gameTime)
        {
            // Draw all fields
            Game.SpriteBatch.Begin();
            Rectangle destination;
            foreach (Field field in fields)
            {
                if (field.GetType() == typeof(BlackHole))
                {
                    destination = new Rectangle(field.FieldPositionX * BlockSize + 1 + OffsetX, field.FieldPositionY * BlockSize + 1 + OffsetY, BlockSize - 1, BlockSize - 1);
                    Game.SpriteBatch.Draw(fieldTextures[field.TextureName], destination, Color.White);
                }
                else
                {
                    destination = new Rectangle(field.FieldPositionX * BlockSize + OffsetX, field.FieldPositionY * BlockSize + OffsetY, BlockSize, BlockSize);
                    Game.SpriteBatch.Draw(fieldTextures[field.TextureName], destination, Color.White);
                }
            }

            foreach (DrawableGameComponent component in drawableComponents)
            {
                component.Draw(gameTime);
            }

            Game.SpriteBatch.End();
        }

        public bool addTower(DrawableGameComponent tower)
        {
            if (tower != null && typeof(IBuilding).IsAssignableFrom(tower.GetType()))
            {
                IBuilding building = tower as IBuilding;
                bool BauplatzOK = false;
                // Die Prüfung ob "hier" etwas gebaut werden kann ist atm sehr umständlich; Datenstrukturen sollten verbessert werden
                foreach (Field field in fields)
                {
                    if (field.FieldPositionX == building.PositionX
                        && field.FieldPositionY == building.PositionY
                        && field.Constructible == true)
                    {
                        BauplatzOK = true;
                        foreach (IBuilding b in buildings)
                        {
                            if (b.PositionX == building.PositionX
                                && b.PositionY == building.PositionY)
                            {
                                BauplatzOK = false;
                                break;
                            }
                        }
                        break;
                    }
                }

                if (BauplatzOK && building.Cost <= player.Money)
                {
                    player.Money -= building.Cost;
                    buildings.Add(building);
                    components.Add(tower);
                    return true;
                }
            }
            return false;
        }
    }
}
